﻿using System.Runtime.CompilerServices;
using NLog;
using Server.Proto;

namespace Geek.Server.DemoClient.Core
{
    public class MsgWaiter
    {
        public class Awaiter : INotifyCompletion
        {
            private Action _callback = () => { };
            private ResponseMessage result = null;
            private Timer timer;
            public bool IsCompleted => cmp;
            public ResponseMessage GetResult() => result;
            public Awaiter GetAwaiter() => this;
            uint uid;
            string msg;
            bool cmp = false;

            public Awaiter(uint uid, string msg)
            {
                this.uid = uid;
                this.msg = msg;
                timer = new Timer(TimeOut, null, 10000, -1);
            }

            public void OnCompleted(Action continuation)
            {
                if (IsCompleted)
                {
                    continuation();
                }
                else
                {
                    _callback += continuation;
                }
            }


            public void Complete(ResponseMessage result)
            {
                if (!cmp)
                {
                    cmp = true;
                    this.result = result;
                    timer.Dispose();
                    _callback();
                }
            }

            void TimeOut(object state)
            {
                Log.Error($"等待消息超时:{uid} {msg} {cmp}");
                Complete(new CommonResp
                {
                    ErrorCode = (int)MessageErrorCode.RequestTimeOut
                });
            }
        }

        private static readonly Logger Log = LogManager.GetCurrentClassLogger();
        private readonly Dictionary<uint, Awaiter> waitDic = new();

        public void Clear()
        {
            foreach (var kv in waitDic)
                kv.Value.Complete(new CommonResp
                {
                    ErrorCode = (int)MessageErrorCode.NetworkClosed,
                });
            waitDic.Clear();
        }

        public Awaiter StartWait(uint uniId, string msg)
        {
            Awaiter waiter = null;
            lock (waitDic)
            {
                if (!waitDic.ContainsKey(uniId))
                {
                    waiter = new Awaiter(uniId, msg);
                    waitDic.Add(uniId, waiter);
                }
                else
                {
                    Log.Error("发现重复消息id：" + uniId);
                }

                return waiter;
            }
        }

        public void EndWait(ResponseMessage response)
        {
            var rpcId = response.RpcId;
            Awaiter waiter = null;
            lock (waitDic)
            {
                if (waitDic.ContainsKey(rpcId))
                {
                    waiter = waitDic[rpcId];
                    waitDic.Remove(rpcId);
                }
                else
                {
                    if (rpcId > 0)
                        Log.Error("找不到EndWait：" + rpcId + ">size：" + waitDic.Count);
                }

                waiter?.Complete(response);
            }
        }
    }
}